"""
枚举基类
"""

import enum
from types import DynamicClassAttribute
from typing import (
    Any,
    Dict,
    List,
    Type,
    Tuple,
    Union,
)

__all__ = [
    "XTextChoices",  # ->       用于创建枚举字符串选项的类
    "XIntegerChoices",  # ->    用于创建枚举整数选择的类
]


class XChoicesMeta(enum.EnumMeta):
    """
    用于创建 enum choices 的元类

    Be modeled after -> `django.db.models.enums.ChoicesMeta`
    """

    def __new__(
            mcs: type,
            class_name: str,
            bases: Tuple[type, ...],
            class_dict: Dict[str, Any],
    ):
        """
        创建一个枚举类

        :param class_name:          类名
        :param bases:               类的基本属性
        :param class_dict:          类的字典信息
        :raise AssertionError1:     请注意格式：name = value, label
        :raise AssertionError2:     label 只能为: str
        :raise AssertionError3:     value 只能为: int/str
        """

        labels: List[str] = []

        for key in getattr(class_dict, "_member_names", []):
            value: Tuple[Union[int, str], str] = class_dict[key]

            assert len(value) == 2, "请注意格式：name = value, label"
            assert isinstance(value[-1], str), "label 只能为: str"
            assert isinstance(value[0], (int, str)), "value 只能为: int/str"

            *value, label = value
            value = tuple(value)
            labels.append(label)
            dict.__setitem__(class_dict, key, value)

        cls: Union[type, enum.Enum] = super().__new__(mcs, class_name, bases, class_dict)
        cls._value2label_map_ = dict(zip(cls._value2member_map_, labels))
        cls.label = property(lambda self: cls._value2label_map_.get(self.value))
        cls.do_not_call_in_templates = True

        return enum.unique(cls)

    def __contains__(cls, member):
        if not isinstance(member, enum.Enum):
            return member in {x.value for x in cls}

        return super().__contains__(member)

    @property
    def name_type(cls) -> Type[str]:
        """ name 的类型 """

        return str

    @property
    def value_type(cls) -> Type[Union[str, int]]:
        """ value 的类型 """

        return type(cls.values[0])

    @property
    def label_type(cls) -> Type[str]:
        """ label 的类型 """

        return str

    @property
    def names(cls) -> Tuple[str, ...]:
        """ 返回所有 name """

        return tuple(member.name for member in cls)

    @property
    def labels(cls) -> Tuple[str, ...]:
        """ 返回所有 label """

        return tuple(member.label for member in cls)

    @property
    def values(cls) -> Tuple[Union[int, str], ...]:
        """ 返回所有 value """

        return tuple(member.value for member in cls)

    @property
    def choices(cls) -> Tuple[Tuple[Union[int, str], str], ...]:
        """ 返回元组，内部元素是元组 (value, label) """

        return tuple((member.value, member.label) for member in cls)

    @property
    def v_l_mapping(cls) -> Dict[Union[int, str], str]:
        """ 返回 value-label 映射 """

        return {member.value: member.label for member in cls}

    @property
    def l_v_mapping(cls) -> Dict[str, Union[int, str]]:
        """ 返回 label-value 映射 """

        return {member.label: member.value for member in cls}

    @property
    def n_v_mapping(cls) -> Dict[Union[int, str], str]:
        """ 返回 name-value 映射 """

        return {member.name: member.value for member in cls}

    @property
    def v_n_mapping(cls) -> Dict[str, Union[int, str]]:
        """ 返回 value-name 映射 """

        return {member.value: member.name for member in cls}

    @property
    def n_l_mapping(cls) -> Dict[Union[int, str], str]:
        """ 返回 name-label 映射 """

        return {member.name: member.label for member in cls}

    @property
    def l_n_mapping(cls) -> Dict[str, Union[int, str]]:
        """ 返回 label-name 映射 """

        return {member.label: member.name for member in cls}


class XChoices(
    enum.Enum,
    metaclass=XChoicesMeta,
):
    """ Class for creating enumerated choices. """

    @DynamicClassAttribute
    def name(self) -> str:
        """ Name """

        return self._name_

    @DynamicClassAttribute
    def label(self) -> str:
        """ Label """

        return self.n_l_mapping[self._name_]

    def __str__(self) -> str:
        return str(self.value)


class XIntegerChoices(
    int,
    XChoices,
):
    """ 用于创建枚举整数选择的类 """

    @DynamicClassAttribute
    def value(self) -> int:
        """ Value """

        return self._value_


class XTextChoices(
    str,
    XChoices,
):
    """ 用于创建枚举字符串选项的类 """

    @DynamicClassAttribute
    def value(self) -> str:
        """ Value """

        return self._value_

    def _generate_next_value_(
            self,
            start,
            count,
            last_values,
    ) -> "XTextChoices":
        return self


'''
# -------------------- XIntegerChoices 用法 --------------------

class Gender(XIntegerChoices):
    """ 性别 枚举类 """

    UNKNOWN = 0, '未知'
    MALE = 1, '男'
    FEMALE = 2, '女'
    SECRET = 3, '保密'


print(Gender.values)        # (0, 1, 2, 3)
print(Gender.labels)        # ('未知', '男', '女', '保密')
print(Gender.names)         # ('UNKNOWN', 'MALE', 'FEMALE', 'SECRET')
print(Gender.choices)       # ((0, '未知'), (1, '男'), (2, '女'), (3, '保密'))
print(Gender.v_l_mapping)   # {0: '未知', 1: '男', 2: '女', 3: '保密'}
print(Gender.l_v_mapping)   # {'未知': 0, '男': 1, '女': 2, '保密': 3}
print(Gender.n_v_mapping)   # {'UNKNOWN': 0, 'MALE': 1, 'FEMALE': 2, 'SECRET': 3}
print(Gender.v_n_mapping)   # {0: 'UNKNOWN', 1: 'MALE', 2: 'FEMALE', 3: 'SECRET'}
print(Gender.n_l_mapping)   # {'UNKNOWN': '未知', 'MALE': '男', 'FEMALE': '女', 'SECRET': '保密'}
print(Gender.l_n_mapping)   # {'未知': 'UNKNOWN', '男': 'MALE', '女': 'FEMALE', '保密': 'SECRET'}



# -------------------- XTextChoices 用法 --------------------

class Direction(XTextChoices):
    """ 方向 枚举类 """

    UP = "up", "上"
    DOWN = "down", "下"
    LEFT = "left", "左"
    RIGHT = "right", "右"


print(Direction.values)         # ('up', 'down', 'left', 'right')
print(Direction.labels)         # ('上', '下', '左', '右')
print(Direction.names)          # ('UP', 'DOWN', 'LEFT', 'RIGHT')
print(Direction.choices)        # (('up', '上'), ('down', '下'), ('left', '左'), ('right', '右'))
print(Direction.v_l_mapping)    # {'up': '上', 'down': '下', 'left': '左', 'right': '右'}
print(Direction.l_v_mapping)    # {'上': 'up', '下': 'down', '左': 'left', '右': 'right'}
print(Direction.n_v_mapping)    # {'UP': 'up', 'DOWN': 'down', 'LEFT': 'left', 'RIGHT': 'right'}
print(Direction.v_n_mapping)    # {'up': 'UP', 'down': 'DOWN', 'left': 'LEFT', 'right': 'RIGHT'}
print(Direction.n_l_mapping)    # {'UP': '上', 'DOWN': '下', 'LEFT': '左', 'RIGHT': '右'}
print(Direction.l_n_mapping)    # {'上': 'UP', '下': 'DOWN', '左': 'LEFT', '右': 'RIGHT'}
'''
